home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / bin / debconf-apt-progress < prev    next >
Encoding:
Text File  |  2009-03-24  |  11.1 KB  |  475 lines

  1. #!/usr/bin/perl -w
  2. # This file was preprocessed, do not edit!
  3.  
  4.  
  5. use strict;
  6. use POSIX;
  7. use Fcntl;
  8. use Getopt::Long;
  9. use Debconf::Client::ConfModule ();
  10.  
  11. my ($config, $start, $from, $to, $stop);
  12. my $progress=1;
  13. my $dlwaypoint=15;
  14. my ($logfile, $logstderr);
  15. my $had_frontend;
  16.  
  17. sub checkopen (@) {
  18.     my $file = $_[0];
  19.     my $fd = POSIX::open($file, &POSIX::O_RDONLY);
  20.     defined $fd or die "$0: can't open $_[0]: $!\n";
  21.     return $fd;
  22. }
  23.  
  24. sub checkclose ($) {
  25.     my $fd = $_[0];
  26.     unless (POSIX::close($fd)) {
  27.         return if $! == &POSIX::EBADF;
  28.         die "$0: can't close fd $fd: $!\n";
  29.     }
  30. }
  31.  
  32. sub checkdup2 ($$) {
  33.     my ($oldfd, $newfd) = @_;
  34.     checkclose($newfd);
  35.     POSIX::dup2($oldfd, $newfd)
  36.         or die "$0: can't dup fd $oldfd to $newfd: $!\n";
  37. }
  38.  
  39. sub nocloexec (*) {
  40.     my $fh = shift;
  41.     my $flags = fcntl($fh, F_GETFD, 0);
  42.     fcntl($fh, F_SETFD, $flags & ~FD_CLOEXEC);
  43. }
  44.  
  45. sub nonblock (*) {
  46.     my $fh = shift;
  47.     my $flags = fcntl($fh, F_GETFL, 0);
  48.     fcntl($fh, F_SETFL, $flags | O_NONBLOCK);
  49. }
  50.  
  51. sub reservefds (@) {
  52.     my $null = checkopen('/dev/null');
  53.     my $close = 1;
  54.     for my $fd (@_) {
  55.         if ($null == $fd) {
  56.             $close = 0;
  57.         } else {
  58.             checkclose($fd);
  59.             checkdup2($null, $fd);
  60.         }
  61.     }
  62.     if ($close) {
  63.         checkclose($null);
  64.     }
  65. }
  66.  
  67. sub envnonempty ($) {
  68.     my $name = shift;
  69.     return (exists $ENV{$name} and $ENV{$name} ne '');
  70. }
  71.  
  72. sub start_debconf (@) {
  73.     if (! $ENV{DEBIAN_HAS_FRONTEND}) {
  74.         if (envnonempty('DEBCONF_DB_REPLACE')) {
  75.             $ENV{DEBCONF_APT_PROGRESS_DB_REPLACE} =
  76.                 $ENV{DEBCONF_DB_REPLACE};
  77.         }
  78.         if (envnonempty('DEBCONF_DB_OVERRIDE')) {
  79.             $ENV{DEBCONF_APT_PROGRESS_DB_OVERRIDE} =
  80.                 $ENV{DEBCONF_DB_OVERRIDE};
  81.         }
  82.  
  83.         $ENV{DEBCONF_DB_REPLACE} = 'configdb';
  84.         $ENV{DEBCONF_DB_OVERRIDE} = 'Pipe{infd:none outfd:none}';
  85.  
  86.         $ENV{DEBCONF_APT_PROGRESS_NO_FRONTEND} = 1;
  87.  
  88.         @ARGV = @_;
  89.     }
  90.  
  91.     import Debconf::Client::ConfModule;
  92. }
  93.  
  94. sub passthrough (@) {
  95.     my $priority = Debconf::Client::ConfModule::get('debconf/priority');
  96.  
  97.     defined(my $pid = fork) or die "$0: can't fork: $!\n";
  98.     if (!$pid) {
  99.         close STATUS_READ;
  100.         close COMMAND_WRITE;
  101.         close DEBCONF_COMMAND_READ;
  102.         close DEBCONF_REPLY_WRITE;
  103.         $^F = 6; # avoid close-on-exec
  104.         if (fileno(COMMAND_READ) != 0) {
  105.             checkdup2(fileno(COMMAND_READ), 0);
  106.             close COMMAND_READ;
  107.         }
  108.         if (fileno(APT_LOG) != 1) {
  109.             checkclose(1);
  110.             checkdup2(fileno(APT_LOG), 1);
  111.         }
  112.         if (fileno(APT_LOG) != 2) {
  113.             checkclose(2);
  114.             checkdup2(fileno(APT_LOG), 2);
  115.         }
  116.         close APT_LOG;
  117.         delete $ENV{DEBIAN_HAS_FRONTEND};
  118.         delete $ENV{DEBCONF_REDIR};
  119.         delete $ENV{DEBCONF_SYSTEMRC};
  120.         delete $ENV{DEBCONF_PIPE}; # just in case ...
  121.         $ENV{DEBIAN_FRONTEND} = 'passthrough';
  122.         $ENV{DEBIAN_PRIORITY} = $priority;
  123.         $ENV{DEBCONF_READFD} = 5;
  124.         $ENV{DEBCONF_WRITEFD} = 6;
  125.         $ENV{APT_LISTCHANGES_FRONTEND} = 'none';
  126.         if ($had_frontend) {
  127.             $ENV{DEBCONF_DB_REPLACE} = 'configdb';
  128.             $ENV{DEBCONF_DB_OVERRIDE} = 'Pipe{infd:none outfd:none}';
  129.         }
  130.         exec @_;
  131.     }
  132.  
  133.     close STATUS_WRITE;
  134.     close COMMAND_READ;
  135.     close DEBCONF_COMMAND_WRITE;
  136.     close DEBCONF_REPLY_READ;
  137.     return $pid;
  138. }
  139.  
  140. sub handle_status ($$$) {
  141.     my ($from, $to, $line) = @_;
  142.     my ($status, $pkg, $percent, $description) = split ':', $line, 4;
  143.  
  144.     my ($min, $len);
  145.     if ($status eq 'dlstatus') {
  146.         $min = 0;
  147.         $len = $dlwaypoint;
  148.     }
  149.     elsif ($status eq 'pmstatus') {
  150.         $min = $dlwaypoint;
  151.         $len = 100 - $dlwaypoint;
  152.     }
  153.     elsif ($status eq 'media-change') {
  154.         Debconf::Client::ConfModule::subst(
  155.             'debconf-apt-progress/media-change', 'MESSAGE',
  156.             $description);
  157.         my @ret = Debconf::Client::ConfModule::input(
  158.             'critical', 'debconf-apt-progress/media-change');
  159.         $ret[0] == 0 or die "Can't display media change request!\n";
  160.         Debconf::Client::ConfModule::go();
  161.         print COMMAND_WRITE "\n" || die "can't talk to command fd: $!";
  162.         return;
  163.     }
  164.     else {
  165.         return;
  166.     }
  167.  
  168.     $percent = ($percent * $len / 100 + $min);
  169.     $percent = ($percent * ($to - $from) / 100 + $from);
  170.     $percent =~ s/\..*//;
  171.     if ($progress) {
  172.         my @ret=Debconf::Client::ConfModule::progress('SET', $percent);
  173.         if ($ret[0] eq '30') {
  174.             cancel();
  175.         }
  176.     }
  177.     Debconf::Client::ConfModule::subst(
  178.         'debconf-apt-progress/info', 'DESCRIPTION', $description);
  179.     my @ret=Debconf::Client::ConfModule::progress(
  180.         'INFO', 'debconf-apt-progress/info');
  181.     if ($ret[0] eq '30') {
  182.         cancel();
  183.     }
  184. }
  185.  
  186. sub handle_debconf_command ($) {
  187.     my $line = shift;
  188.  
  189.     print "$line\n" || die "can't write to stdout: $!";
  190.     my $ret = <STDIN>;
  191.     chomp $ret;
  192.     print DEBCONF_REPLY_WRITE "$ret\n" ||
  193.         die "can't write to DEBCONF_REPLY_WRITE: $!";
  194. }
  195.  
  196. my $pid;
  197. sub run_progress ($$@) {
  198.     my $from = shift;
  199.     my $to = shift;
  200.     my $command = shift;
  201.     local (*STATUS_READ, *STATUS_WRITE);
  202.     local (*COMMAND_READ, *COMMAND_WRITE);
  203.     local (*DEBCONF_COMMAND_READ, *DEBCONF_COMMAND_WRITE);
  204.     local (*DEBCONF_REPLY_READ, *DEBCONF_REPLY_WRITE);
  205.     local *APT_LOG;
  206.     use IO::Handle;
  207.  
  208.     if ($progress) {
  209.         my @ret=Debconf::Client::ConfModule::progress(
  210.             'INFO', 'debconf-apt-progress/preparing');
  211.         if ($ret[0] eq '30') {
  212.             cancel();
  213.         }
  214.     }
  215.  
  216.     reservefds(4, 5, 6);
  217.  
  218.     pipe STATUS_READ, STATUS_WRITE
  219.         or die "$0: can't create status pipe: $!";
  220.     nonblock(\*STATUS_READ);
  221.     checkdup2(fileno(STATUS_WRITE), 4);
  222.     open STATUS_WRITE, '>&=4'
  223.         or die "$0: can't reopen STATUS_WRITE as fd 4: $!";
  224.     nocloexec(\*STATUS_WRITE);
  225.  
  226.     pipe COMMAND_READ, COMMAND_WRITE
  227.         or die "$0: can't create command pipe: $!";
  228.     nocloexec(\*COMMAND_READ);
  229.     COMMAND_WRITE->autoflush(1);
  230.  
  231.     pipe DEBCONF_COMMAND_READ, DEBCONF_COMMAND_WRITE
  232.         or die "$0: can't create debconf command pipe: $!";
  233.     nonblock(\*DEBCONF_COMMAND_READ);
  234.     checkdup2(fileno(DEBCONF_COMMAND_WRITE), 6);
  235.     open DEBCONF_COMMAND_WRITE, '>&=6'
  236.         or die "$0: can't reopen DEBCONF_COMMAND_WRITE as fd 6: $!";
  237.     nocloexec(\*DEBCONF_COMMAND_WRITE);
  238.  
  239.     pipe DEBCONF_REPLY_READ, DEBCONF_REPLY_WRITE
  240.         or die "$0: can't create debconf reply pipe: $!";
  241.     checkdup2(fileno(DEBCONF_REPLY_READ), 5);
  242.     open DEBCONF_REPLY_READ, '<&=5'
  243.         or die "$0: can't reopen DEBCONF_REPLY_READ as fd 5: $!";
  244.     nocloexec(\*DEBCONF_REPLY_READ);
  245.     DEBCONF_REPLY_WRITE->autoflush(1);
  246.  
  247.     if (defined $logfile) {
  248.         open APT_LOG, '>>', $logfile
  249.             or die "$0: can't open $logfile: $!";
  250.     } elsif ($logstderr) {
  251.         open APT_LOG, '>&STDERR'
  252.             or die "$0: can't duplicate stderr: $!";
  253.     } else {
  254.         open APT_LOG, '>', '/dev/null'
  255.             or die "$0: can't open /dev/null: $!";
  256.     }
  257.     nocloexec(\*APT_LOG);
  258.  
  259.     $pid = passthrough $command,
  260.         '-o', 'APT::Status-Fd=4',
  261.         '-o', 'APT::Keep-Fds::=5',
  262.         '-o', 'APT::Keep-Fds::=6',
  263.         @_;
  264.  
  265.     my $status_eof = 0;
  266.     my $debconf_command_eof = 0;
  267.     my $status_buf = '';
  268.     my $debconf_command_buf = '';
  269.  
  270.     while (not $status_eof) {
  271.         my $rin = '';
  272.         my $rout;
  273.         vec($rin, fileno(STATUS_READ), 1) = 1;
  274.         vec($rin, fileno(DEBCONF_COMMAND_READ), 1) = 1
  275.             unless $debconf_command_eof;
  276.         my $sel = select($rout = $rin, undef, undef, undef);
  277.         if ($sel < 0) {
  278.             next if $! == &POSIX::EINTR;
  279.             die "$0: select failed: $!";
  280.         }
  281.  
  282.         if (vec($rout, fileno(STATUS_READ), 1) == 1) {
  283.             while (1) {
  284.                 my $r = sysread(STATUS_READ, $status_buf, 4096,
  285.                         length $status_buf);
  286.                 if (not defined $r) {
  287.                     next if $! == &POSIX::EINTR;
  288.                     last if $! == &POSIX::EAGAIN or
  289.                         $! == &POSIX::EWOULDBLOCK;
  290.                     die "$0: read STATUS_READ failed: $!";
  291.                 }
  292.                 elsif ($r == 0) {
  293.                     if ($status_buf ne '' and
  294.                         $status_buf !~ /\n$/) {
  295.                         $status_buf .= "\n";
  296.                     }
  297.                     $status_eof = 1;
  298.                     last;
  299.                 }
  300.                 last if $status_buf =~ /\n/;
  301.             }
  302.  
  303.             while ($status_buf =~ /\n/) {
  304.                 my $status_line;
  305.                 ($status_line, $status_buf) =
  306.                     split /\n/, $status_buf, 2;
  307.                 handle_status $from, $to, $status_line;
  308.             }
  309.         }
  310.  
  311.         if (vec($rout, fileno(DEBCONF_COMMAND_READ), 1) == 1) {
  312.             while (1) {
  313.                 my $r = sysread(DEBCONF_COMMAND_READ,
  314.                         $debconf_command_buf, 4096,
  315.                         length $debconf_command_buf);
  316.                 if (not defined $r) {
  317.                     next if $! == &POSIX::EINTR;
  318.                     last if $! == &POSIX::EAGAIN or
  319.                         $! == &POSIX::EWOULDBLOCK;
  320.                     die "$0: read DEBCONF_COMMAND_READ " .
  321.                         "failed: $!";
  322.                 }
  323.                 elsif ($r == 0) {
  324.                     if ($debconf_command_buf ne '' and
  325.                         $debconf_command_buf !~ /\n$/) {
  326.                         $debconf_command_buf .= "\n";
  327.                     }
  328.                     $debconf_command_eof = 1;
  329.                     last;
  330.                 }
  331.                 last if $debconf_command_buf =~ /\n/;
  332.             }
  333.  
  334.             while ($debconf_command_buf =~ /\n/) {
  335.                 my $debconf_command_line;
  336.                 ($debconf_command_line, $debconf_command_buf) =
  337.                     split /\n/, $debconf_command_buf, 2;
  338.                 handle_debconf_command $debconf_command_line;
  339.             }
  340.         }
  341.     }
  342.  
  343.     waitpid $pid, 0;
  344.     my $status = $?;
  345.  
  346.     Debconf::Client::ConfModule::progress('SET', $to) if $progress;
  347.  
  348.     if ($status & 127) {
  349.         return 127;
  350.     }
  351.  
  352.     return ($status >> 8);
  353. }
  354.  
  355. my $cancelled=0;
  356. sub cancel () {
  357.     if (defined $pid) {
  358.         $cancelled++;
  359.         if ($cancelled == 1) {
  360.             kill INT => $pid;
  361.         }
  362.         else {
  363.             kill KILL => $pid;
  364.         }
  365.     }
  366. }
  367.  
  368. sub start_bar ($$) {
  369.     my ($from, $to) = @_;
  370.     if ($progress) {
  371.         Debconf::Client::ConfModule::progress(
  372.             'START', $from, $to, 'debconf-apt-progress/title');
  373.         my @ret=Debconf::Client::ConfModule::progress(
  374.             'INFO', 'debconf-apt-progress/preparing');
  375.         if ($ret[0] eq '30') {
  376.             cancel();
  377.         }
  378.     }
  379. }
  380.  
  381. sub stop_bar () {
  382.     Debconf::Client::ConfModule::progress('STOP') if $progress;
  383.     Debconf::Client::ConfModule::stop() unless $had_frontend;
  384. }
  385.  
  386. if (envnonempty('DEBCONF_APT_PROGRESS_DB_REPLACE')) {
  387.     $ENV{DEBCONF_DB_REPLACE} = $ENV{DEBCONF_APT_PROGRESS_DB_REPLACE};
  388. } else {
  389.     delete $ENV{DEBCONF_DB_REPLACE};
  390. }
  391. if (envnonempty('DEBCONF_APT_PROGRESS_DB_OVERRIDE')) {
  392.     $ENV{DEBCONF_DB_OVERRIDE} = $ENV{DEBCONF_APT_PROGRESS_DB_OVERRIDE};
  393. } else {
  394.     delete $ENV{DEBCONF_DB_OVERRIDE};
  395. }
  396. $had_frontend = 1 unless $ENV{DEBCONF_APT_PROGRESS_NO_FRONTEND};
  397. delete $ENV{DEBCONF_APT_PROGRESS_NO_FRONTEND}; # avoid inheritance
  398.  
  399. my @saved_argv = @ARGV;
  400.  
  401. my $result = GetOptions('config'       => \$config,
  402.             'start'        => \$start,
  403.             'from=i'       => \$from,
  404.             'to=i'         => \$to,
  405.             'stop'         => \$stop,
  406.             'logfile=s'    => \$logfile,
  407.             'logstderr'    => \$logstderr,
  408.             'progress!'    => \$progress,
  409.             'dlwaypoint=i' => \$dlwaypoint,
  410. );
  411.  
  412. if (! $progress && ($start || $from || $to || $stop)) {
  413.     die "--no-progress cannot be used with --start, --from, --to, or --stop\n";
  414. }
  415.  
  416. unless ($start) {
  417.     if (defined $from and not defined $to) {
  418.         die "$0: --from requires --to\n";
  419.     } elsif (defined $to and not defined $from) {
  420.         die "$0: --to requires --from\n";
  421.     }
  422. }
  423.  
  424. my $mutex = 0;
  425. ++$mutex if $config;
  426. ++$mutex if $start;
  427. ++$mutex if $stop;
  428. if ($mutex > 1) {
  429.     die "$0: must use only one of --config, --start, or --stop\n";
  430. }
  431.  
  432. if (($config or $stop) and (defined $from or defined $to)) {
  433.     die "$0: cannot use --from or --to with --config or --stop\n";
  434. }
  435.  
  436. start_debconf(@saved_argv) unless $config;
  437.  
  438. my $status = 0;
  439.  
  440. if ($config) {
  441.     print <<'EOF';
  442. DEBCONF_APT_PROGRESS_DB_REPLACE="$DEBCONF_DB_REPLACE"
  443. DEBCONF_APT_PROGRESS_DB_OVERRIDE="$DEBCONF_DB_OVERRIDE"
  444. export DEBCONF_APT_PROGRESS_DB_REPLACE DEBCONF_APT_PROGRESS_DB_OVERRIDE
  445. DEBCONF_DB_REPLACE=configdb
  446. DEBCONF_DB_OVERRIDE='Pipe{infd:none outfd:none}'
  447. export DEBCONF_DB_REPLACE DEBCONF_DB_OVERRIDE
  448. EOF
  449. } elsif ($start) {
  450.     $from = 0 unless defined $from;
  451.     $to = 100 unless defined $to;
  452.     start_bar($from, $to);
  453. } elsif (defined $from) {
  454.     $status = run_progress($from, $to, @ARGV);
  455. } elsif ($stop) {
  456.     stop_bar();
  457. } else {
  458.     start_bar(0, 100);
  459.     $status = run_progress(0, 100, @ARGV);
  460.     stop_bar();
  461. }
  462.  
  463. if ($cancelled) {
  464.     Debconf::Client::ConfModule::get("debconf/priority");
  465.  
  466.     exit 30;
  467. }
  468. elsif ($status == 30) {
  469.     exit 3;
  470. }
  471. else {
  472.     exit $status;
  473. }
  474.  
  475.